#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#define mid (l+r)/2
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ll long long
using namespace std;
const int N=1e6+10;
struct node{
    int d,v,a;
}k[N];
struct node2{
    int l,r;
}a[N];
ll dp[N][2];
ll T,n,m,L,v,tr[N*4],top,ans1;
ll b[N];
bool cmp(node2 x,node2 y){
    if(x.l==y.l) return x.r<y.r;
    return x.l<y.l;
}
void pushup(int id){
    tr[id]=min(tr[id*2],tr[id*2+1]);
}
void change(int id,int l,int r,int x,int v)
{
    //cout<<id<<" "<<l<<" "<<r<<endl;//if(id==0) exit(0);
    if(l==r){
        if(l==x) tr[id]=v;
        return;
    }
    if(x<=mid) change(lson,x,v);
    else change(rson,x,v);
    pushup(id);
}
int query(int id,int l,int r,int x,int y){
    //cout<<id<<" "<<l<<" "<<r<<" "<<x<<" "<<y<<endl;//if(id==-1) exit(0);
    if(x<=l&&r<=y){
        return tr[id];
    }
    int ans=0x3f3f3f3f;
    if(x<=mid) ans=min(ans,query(lson,x,y));
    if(y>mid) ans=min(ans,query(rson,x,y));
    return ans;
}
vector<int> G[N];
int low(ll x,ll dt)
{
    int l=1,r=m,ans;
    while(l<=r){
        if(b[mid]*dt<=x){
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }

}
int main()
{
    freopen("detect.in","r",stdin);
    freopen("detect.out","w",stdout);
    scanf("%d",&T);
    for(int o=1;o<=T;o++){ans1=0;top=0;
        scanf("%lld%lld%lld%lld",&n,&m,&L,&v);
        for(int i=1;i<=n;i++)
            scanf("%lld%lld%lld",&k[i].d,&k[i].v,&k[i].a);
        for(int i=1;i<=m;i++)
            scanf("%lld",&b[i]);
        for(int i=1;i<=n;i++){
            if(k[i].a==0){
                if(k[i].v>v){
                    if(k[i].d<=b[m]){
                        int s=lower_bound(b+1,b+1+m,k[i].d)-b;
                        a[++top].l=s;
                        a[top].r=L;
                        ans1++;
                    }
                }
            }
            if(k[i].a>0){
                ll l=(v*v-k[i].v*k[i].v)+k[i].d*2*k[i].a;
                int s=low(l,2*k[i].a);
                if((v*v-k[i].v*k[i].v)+k[i].d*2*k[i].a==b[s]*2*k[i].a) s++;
                if(s<=m){
                    a[++top].l=s;
                    a[top].r=L;
                    ans1++;
                }
            }
            if(k[i].a<0&&k[i].v>v){
                int s1=lower_bound(b+1,b+1+m,k[i].d)-b;
                ll l=k[i].v*k[i].v-v*v+k[i].d*2*(-k[i].a);
                ll s2=low(l,2*(-k[i].a))-1;
                //if(1.0*(k[i].v*k[i].v-v*v)/2/(-k[i].a)+k[i].d==b[s2]) s2--;
                //cout<<s1<<" "<<s2<<endl;
                s2=min(m,s2);
                if(s1<=s2){
                    a[++top].l=s1;
                    a[top].r=s2;
                    ans1++;
                }
            }
        }
        for(int i=1;i<=L;i++)
            G[i].clear();
        sort(a+1,a+1+top,cmp);
        int k=0x3f3f3f3f;
        memset(dp,0x3f,sizeof(dp));
        memset(tr,0x3f,sizeof(tr));
        for(int i=1;i<=top;i++)
            G[a[i].l].push_back(i);
        dp[L+1][0]=0;
        for(int i=L;i>=0;i--){
            for(auto x:G[i])
                k=min(k,a[x].r);
            dp[i][1]=min(dp[i+1][0],dp[i+1][1])+1;
            change(1,0,L,i,dp[i][1]);
            //cout<<query(1,0,L,i,i)<<" "<<dp[i][1]<<endl;
            int tp=0x3f3f3f3f;
            if(G[i].size()==0) tp=min(dp[i+1][0],dp[i+1][1]);
            else{
                 //for(int j=i+1;j<=k;j++)
            //tp=min(tp,dp[j][1]);
            tp=query(1,0,L,i+1,k);
            }
            dp[i][0]=tp;
        }
        printf("%d %d\n",ans1,m-min(dp[1][0],dp[1][1]));
    }
    return 0;
}
/*
3
3
1 2 1
4
1 2 3 4
8
3 5 2 5 1 2 1 4
*/
